
#include "ctc_const.h"
#include "ctc_error.h"
#include "sys_usw_common.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_register.h"
#include "sys_usw_ftm.h"
#include "sys_usw_wb_nh.h"
#include "drv_api.h"

struct sys_nh_fp_data_raw_s
{
    uint8 cnt;
    uint8 pos;
};
typedef struct sys_nh_fp_data_raw_s sys_nh_fp_data_raw_t;

STATIC uint32
_sys_tmm_nh_fp_spool_make(sys_nh_fp_prof_t* p_prof)
{
    return ctc_hash_caculate(sizeof(p_prof->data) + sizeof(uint8), p_prof);
}


 /* if vlan edit in bucket equals */
STATIC bool
_sys_tmm_nh_fp_spool_cmp(sys_nh_fp_prof_t* p0,
                                          sys_nh_fp_prof_t* p1)
{
    if (!p0 || !p1)
    {
        return FALSE;
    }

    if (p0->type== p1->type &&
        !sal_memcmp(p0, p1, sizeof(p0->data)))
    {
        return TRUE;
    }

    return FALSE;
}

STATIC int32
_sys_tmm_nh_fp_spool_alloc_index(sys_nh_fp_prof_t* p_prof, void* user_data)
{
    uint8 lchip = *(uint8*)user_data;
    uint32 profile_id = 0;
    int32 ret = 0;

    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        ret = sys_usw_nh_offset_alloc_from_position(lchip, p_prof->type, 1, p_prof->profile_id);
        goto end;
    }

    if (p_prof->profile_id)
    {
        ret = sys_usw_nh_offset_alloc_from_position(lchip,
                                                    p_prof->type,
                                                    1, p_prof->profile_id);
        profile_id = p_prof->profile_id;
    }
    else
    {
        ret = sys_usw_nh_offset_alloc(lchip,
                                      p_prof->type,
                                      1, &profile_id);
    }

    if(ret)
    {
        return ret;
    }

    p_prof->profile_id = profile_id;
end:
    return ret;
}

STATIC int32
_sys_tmm_nh_fp_spool_free_index(sys_nh_fp_prof_t* p_prof, void* user_data)
{
    uint8 lchip = *(uint8*)user_data;
    int32 ret = 0;

    CTC_PTR_VALID_CHECK(p_prof);

    ret = sys_usw_nh_offset_free(lchip, p_prof->type, 1, p_prof->profile_id);

    return ret;
}

STATIC int32
_sys_tmm_nh_fp_hash_make(sys_nh_fp_db_t* p_data)
{
    return ctc_hash_caculate(sizeof(uint32), &(p_data->fp_id));
}

STATIC bool
_sys_tmm_nh_fp_hash_cmp(sys_nh_fp_db_t* p_data0, sys_nh_fp_db_t* p_data1)
{
    if (!p_data0 || !p_data1)
    {
        return TRUE;
    }

    if (p_data0->fp_id == p_data1->fp_id)
    {
        return TRUE;
    }

    return FALSE;
}

STATIC int32
_sys_tmm_nh_fp_init_reg(uint8 lchip)
{
    uint32 cmd = 0;
    uint32 value = 0;
    uint8 loop = 0;
    DsFlexEditTemplate4_m t4;
    EpePktRw16BitCtl_m rw16;
    EpeXEditCtl_m epe_xedit_ctl;
    EpePktProcXCtl_m epe_pkt_proc_ctl;

    sal_memset(&t4, 0, sizeof(t4));
    sal_memset(&rw16, 0, sizeof(rw16));

    SetDsFlexEditTemplate4(V, g0_0_data_f, &t4, 1);
    SetDsFlexEditTemplate4(V, g0_1_data_f, &t4, 2);
    SetDsFlexEditTemplate4(V, g0_2_data_f, &t4, 4);
    SetDsFlexEditTemplate4(V, g0_3_data_f, &t4, 8);

    SetDsFlexEditTemplate4(V, g1_0_data_f, &t4, 1);
    SetDsFlexEditTemplate4(V, g1_1_data_f, &t4, 2);
    SetDsFlexEditTemplate4(V, g1_2_data_f, &t4, 4);
    SetDsFlexEditTemplate4(V, g1_3_data_f, &t4, 8);

    SetDsFlexEditTemplate4(V, g2_0_data_f, &t4, 1);
    SetDsFlexEditTemplate4(V, g2_1_data_f, &t4, 2);
    SetDsFlexEditTemplate4(V, g2_2_data_f, &t4, 4);
    SetDsFlexEditTemplate4(V, g2_3_data_f, &t4, 8);

    SetDsFlexEditTemplate4(V, g3_0_data_f, &t4, 1);
    SetDsFlexEditTemplate4(V, g3_1_data_f, &t4, 2);
    SetDsFlexEditTemplate4(V, g3_2_data_f, &t4, 4);
    SetDsFlexEditTemplate4(V, g3_3_data_f, &t4, 8);

    cmd = DRV_IOW(DsFlexEditTemplate4_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &t4));

    for(loop = 0; loop < 16; loop++)
    {
        value = (1 <<(loop + 1))-1;
        SetEpePktRw16BitCtl(V, g_0_mask_f + loop, &rw16, value);
    }
    cmd = DRV_IOW(EpePktRw16BitCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &rw16));

    /*init stage2 edit global register*/
    cmd = DRV_IOR(EpeXEditCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_xedit_ctl));

    /*0b' 1110 1111 0100 1100*/
    SetEpeXEditCtl(V, overwriteXContainer_f, &epe_xedit_ctl, 0xEF4C);
    cmd = DRV_IOW(EpeXEditCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_xedit_ctl));


    /*init flex edit xdata map to container*/
    cmd = DRV_IOR(EpePktProcXCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_pkt_proc_ctl));

    SetEpePktProcXCtl(V, g0FlexContainer_0_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g0FlexContainer_1_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g0FlexContainer_2_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g0FlexContainer_0_nibble_f, &epe_pkt_proc_ctl, 0);
    SetEpePktProcXCtl(V, g0FlexContainer_1_nibble_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g0FlexContainer_2_nibble_f, &epe_pkt_proc_ctl, 2);

    SetEpePktProcXCtl(V, g1FlexContainer_0_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_1_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_2_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_3_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_4_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_5_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_6_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_0_byteId_f, &epe_pkt_proc_ctl, 0);
    SetEpePktProcXCtl(V, g1FlexContainer_1_byteId_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g1FlexContainer_2_byteId_f, &epe_pkt_proc_ctl, 2);
    SetEpePktProcXCtl(V, g1FlexContainer_3_byteId_f, &epe_pkt_proc_ctl, 3);
    SetEpePktProcXCtl(V, g1FlexContainer_4_byteId_f, &epe_pkt_proc_ctl, 4);
    SetEpePktProcXCtl(V, g1FlexContainer_5_byteId_f, &epe_pkt_proc_ctl, 5);
    SetEpePktProcXCtl(V, g1FlexContainer_6_byteId_f, &epe_pkt_proc_ctl, 6);

    SetEpePktProcXCtl(V, g2FlexContainer_0_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_1_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_2_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_3_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_4_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_5_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_6_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_0_word_f, &epe_pkt_proc_ctl, 0);
    SetEpePktProcXCtl(V, g2FlexContainer_1_word_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g2FlexContainer_2_word_f, &epe_pkt_proc_ctl, 2);
    SetEpePktProcXCtl(V, g2FlexContainer_3_word_f, &epe_pkt_proc_ctl, 3);
    SetEpePktProcXCtl(V, g2FlexContainer_4_word_f, &epe_pkt_proc_ctl, 4);
    SetEpePktProcXCtl(V, g2FlexContainer_5_word_f, &epe_pkt_proc_ctl, 5);
    SetEpePktProcXCtl(V, g2FlexContainer_6_word_f, &epe_pkt_proc_ctl, 6);

    SetEpePktProcXCtl(V, g3FlexContainer_0_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g3FlexContainer_1_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g3FlexContainer_2_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g3FlexContainer_3_enable_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g3FlexContainer_0_dword_f, &epe_pkt_proc_ctl, 0);
    SetEpePktProcXCtl(V, g3FlexContainer_1_dword_f, &epe_pkt_proc_ctl, 1);
    SetEpePktProcXCtl(V, g3FlexContainer_2_dword_f, &epe_pkt_proc_ctl, 2);
    SetEpePktProcXCtl(V, g3FlexContainer_3_dword_f, &epe_pkt_proc_ctl, 3);
    cmd = DRV_IOW(EpePktProcXCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_pkt_proc_ctl));

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_nh_get_raw_data_sel(uint8 lchip,
                        uint8 id,
                        sys_dsl3edit_fp_t* p_fp,
                        ctc_nh_fp_data_t* p_data,
                        uint8* p_sel)
{
    if (id == 0)
    {
        if (p_data->value == 1)
        {
            *p_sel = 4;
        }
        else if(p_data->value == 2)
        {
            *p_sel = 5;
        }
        else if(p_data->value == 4)
        {
            *p_sel = 6;
        }
        else if(p_data->value == 8)
        {
            *p_sel = 7;
        }
    }
    else if(id == 1)
    {

    }
    else if(id == 2)
    {

    }
    else if(id == 3)
    {

    }

    return 0;

}

STATIC int32
_sys_tmm_nh_get_fp_field_sel(uint8 lchip,
                            sys_dsl3edit_fp_t* p_fp,
                            sys_nh_fp_data_raw_t raw[],
                            ctc_nh_fp_data_t* p_data,
                            uint8* p_container_type,
                            uint8* p_sel)
{
   uint8 sel = 0;
   uint8 id = 0;
   uint8 width = 0;

    switch(p_data->type)
    {
    case CTC_NH_FP_DATA_RAW:
        if (p_data->len <= 4)
        {
            id = 0;
            width = 4;
        }
        else if(p_data->len <= 8)
        {
            id = 1;
            width = 8;
        }
        else if(p_data->len <= 16)
        {
            id = 2;
            width = 16;
        }
        else if(p_data->len <= 32)
        {
            id = 3;
            width = 32;
        }

        _sys_tmm_nh_get_raw_data_sel(lchip, id, p_fp, p_data, &sel);
        if (sel == 0)
        {
            uint8 base[4] = {8, 20, 20, 18};

            CTC_BMP_COPY_RANGE(p_fp->raw_data, raw[id].pos * width , &p_data->value,  0, width);
            if (id == 3)
            {
                sel = raw[id].pos*2 + base[id];
            }
            else
            {
                sel = raw[id].pos + base[id];
            }

            raw[id].pos++;
        }

        break;

    case CTC_NH_FP_DATA_PACKET:
        id = 3;
        sel = 4 + p_data->shift/32;
        break;

    case CTC_NH_FP_DATA_SRC_PORT:
        id = 2;
        sel = 4;
        break;

    case CTC_NH_FP_DATA_DST_PORT:
        id = 2;
        sel = 5;
        break;

    case CTC_NH_FP_DATA_SRC_LPORT:
        id = 2;
        sel = 12;
        break;

    case CTC_NH_FP_DATA_DST_LPORT:
        id = 2;
        sel = 13;
        break;

    case CTC_NH_FP_DATA_HASH_VALUE:
        id = 1;
        sel = 6;
        break;

    case CTC_NH_FP_DATA_QUEUE_ID:
        id = 1;
        sel = 7;
        break;

    case CTC_NH_FP_DATA_L3_PROTOCOL:
        id = 1;
        sel = 8;
        break;

    case CTC_NH_FP_DATA_SRC_VLAN_PTR:
        id = 2;
        sel = 6;
        break;

    case CTC_NH_FP_DATA_L3_INTF:
        id = 2;
        sel = 7;
        break;

    case CTC_NH_FP_DATA_LOGIC_SRC_PORT:
        id = 2;
        sel = 8;
        break;

    case CTC_NH_FP_DATA_LOGIC_DST_PORT:
        id = 2;
        sel = 9;
        break;

    case CTC_NH_FP_DATA_QUEUE_DEPTH:
        id = 2;
        sel = 10;
        break;

    case CTC_NH_FP_DATA_SPAN_ID:
        id = 2;
        sel = 11;
        break;

    case CTC_NH_FP_DATA_FLEX_LEN:
        id = 1;
        sel = 9;
        break;

    case CTC_NH_FP_DATA_TTL:
        id = 1;
        sel = 10;
        break;

    case CTC_NH_FP_DATA_IP_LEN:
        id = 2;
        sel = 14;
        break;

    case CTC_NH_FP_DATA_LATENCY:
        id = 3;
        sel = 10;
        break;

    case CTC_NH_FP_DATA_LOAD_METRIC:
        id = 3;
        sel = 13;
        break;

    case CTC_NH_FP_DATA_TS_HIGH:
        id = 3;
        sel = 8;
        break;

    case CTC_NH_FP_DATA_TS_LOW:
        id = 3;
        sel = 9;
        break;

    case CTC_NH_FP_DATA_IGS_TS:
        id = 3;
        sel = 11;
        break;

    case CTC_NH_FP_DATA_EGS_TS:
        id = 3;
        sel = 12;
        break;

    case CTC_NH_FP_DATA_IGS_TS_HIGH:
        id = 3;
        sel = 25;
        break;

    case CTC_NH_FP_DATA_IGS_TS_LOW:
        id = 3;
        sel = 26;
        break;

    case CTC_NH_FP_DATA_XDATA:
        if (p_data->len == 0 || p_data->len > 16)
        {
            id = 3;
            sel = 27+p_data->src_offset/32;
        }
        else if(p_data->len > 8)
        {
            if(p_data->src_offset >= 112)
            {
                return CTC_E_NOT_SUPPORT;
            }
            id = 2;
            sel = 24 + p_data->src_offset/16;
        }
        else if(p_data->len > 4)
        {
            if(p_data->src_offset >= 56)
            {
                return CTC_E_NOT_SUPPORT;
            }
            id = 1;
            sel = 24 + p_data->src_offset/8;
        }
        else
        {
            if(p_data->src_offset >= 12)
            {
                return CTC_E_NOT_SUPPORT;
            }
            id = 0;
            sel = 12 + p_data->src_offset/4;
        }
        break;

    default:
        return CTC_E_NOT_SUPPORT;
        break;

    }
    *p_container_type = id;
    *p_sel = sel;

    return 0;
}

STATIC int32
_sys_tmm_nh_get_fp2_field_sel(uint8 lchip,
                            sys_dsl3edit_fp_t* p_fp,
                            sys_nh_fp_data_raw_t raw[],
                            ctc_nh_fp_data_t* p_data,
                            uint8* p_container_type,
                            uint8* p_sel)
{
    uint8 sel = 0;
    uint8 id = 0;
    uint8 width = 0;
    uint8 xdata_position = 0;

    switch(p_data->type)
    {
    case CTC_NH_FP_DATA_XDATA:
        if (p_data->len <= 4)
        {
            id = 0;
            xdata_position = p_data->src_offset/4;
            if(xdata_position <= 9 || xdata_position == 11 || xdata_position == 12)
            {
                sel = xdata_position;
            }
            else
            {
                return CTC_E_NOT_SUPPORT;
            }
        }
        else if(p_data->len <= 8)
        {
            id = 1;
            xdata_position = p_data->src_offset/8;
            sel = xdata_position + 11;
        }
        else if(p_data->len <= 16)
        {
            id = 2;
            xdata_position = p_data->src_offset/16;
            sel = xdata_position + 19;
        }
        else if(p_data->len <= 32)
        {
            id = 3;
            xdata_position = p_data->src_offset/32;
            sel = xdata_position + 4;
        }
        break;
    case CTC_NH_FP_DATA_RAW:
        if (p_data->len <= 4)
        {
            id = 0;
            width = 4;
        }
        else if(p_data->len <= 8)
        {
            id = 1;
            width = 8;
        }
        else if(p_data->len <= 16)
        {
            id = 2;
            width = 16;
        }
        else if(p_data->len <= 32)
        {
            id = 3;
            width = 32;
        }

        {
            uint8 base[4] = {11, 27, 27, 28};
            CTC_BMP_COPY_RANGE(p_fp->raw_data, raw[id].pos * width , &p_data->value,  0, width);
            if (id == 3)
            {
                sel = raw[id].pos*2 + base[id];
            }
            else
            {
                sel = raw[id].pos + base[id];
            }
            raw[id].pos++;
        }
        break;
    case CTC_NH_FP_DATA_PACKET:
        id = 3;
        sel = 3 - p_data->shift/32;
        break;

    case CTC_NH_FP_DATA_SRC_PORT:
        id = 2;
        sel = 0;
        break;

    case CTC_NH_FP_DATA_DST_PORT:
        id = 2;
        sel = 1;
        break;

    case CTC_NH_FP_DATA_SRC_LPORT:
        id = 2;
        sel = 8;
        break;

    case CTC_NH_FP_DATA_DST_LPORT:
        id = 2;
        sel = 9;
        break;

     case CTC_NH_FP_DATA_L3_PROTOCOL:
        id = 1;
        sel = 4;
        break;

    case CTC_NH_FP_DATA_SRC_VLAN_PTR:
        id = 2;
        sel = 2;
        break;

    case CTC_NH_FP_DATA_L3_INTF:
        id = 2;
        sel = 3;
        break;

    case CTC_NH_FP_DATA_LOGIC_SRC_PORT:
        id = 2;
        sel = 4;
        break;

    case CTC_NH_FP_DATA_LOGIC_DST_PORT:
        id = 2;
        sel = 5;
        break;

    case CTC_NH_FP_DATA_QUEUE_DEPTH:
        id = 2;
        sel = 6;
        break;

    case CTC_NH_FP_DATA_SPAN_ID:
        id = 2;
        sel = 7;
        break;

    case CTC_NH_FP_DATA_FLEX_LEN:
        id = 1;
        sel = 5;
        break;
    case CTC_NH_FP_DATA_TTL:
        id = 1;
        sel = 6;
        break;
    case CTC_NH_FP_DATA_FID:
        id = 2;
        sel = 10;
        break;
    case CTC_NH_FP_DATA_VNI_ID:
        if(p_data->len > 16)
        {
            id = 3;
            sel = 8;
        }
        else if(p_data->len > 8)
        {
            id = 2;
            sel = 18;
        }
        else
        {
            id = 1;
            sel = 0;
        }
        break;
    case CTC_NH_FP_DATA_SRC_CID:
        if(p_data->len > 8)
        {
            id = 2;
            sel = 17;
        }
        else
        {
            id = 1;
            sel = 1;
        }
        break;
    case CTC_NH_FP_DATA_L4_SRC_PORT_LOW:
        id = 1;
        sel = 7;
        break;
    case CTC_NH_FP_DATA_L4_SRC_PORT_HIGH:
        id = 1;
        sel = 8;
        break;
    case CTC_NH_FP_DATA_L4_DST_PORT_LOW:
        id = 1;
        sel = 9;
        break;
    case CTC_NH_FP_DATA_L4_DST_PORT_HIGH:
        id = 1;
        sel = 10;
        break;
    case CTC_NH_FP_DATA_PRI_COLOR:
        id = 1;
        sel = 28;
        break;
    case CTC_NH_FP_DATA_l3_TYPE:
        id = 1;
        sel = 27;
        break;
    case CTC_NH_FP_DATA_ESLB:
        id = 3;
        sel = 9;
        break;
    default:
        return CTC_E_NOT_SUPPORT;
        break;

    }
    *p_container_type = id;
    *p_sel = sel;

    return 0;
}

#define SYS_NH_FP_SPECIAL_VAL(val) (val == 1 || val == 2 || val == 4 || val == 8)
#define SYS_NH_FP_MAX_OFFSET 126
#define SYS_NH_FP_INS_MAX_LEGTH 56
#define SYS_NH_FP_DEL_MAX_LEGTH 126
#define SYS_NH_FP_HASH_SIZE 2048
STATIC int32
_sys_tmm_nh_fp_check(uint8 lchip,
                    ctc_nh_fp_edit_t* p_fp_edit,
                    uint8* ext_mode, sys_nh_fp_data_raw_t raw[])
{
    uint8 i = 0;
    uint8 alu_cnt = 0;
    uint16 sum_len = 0;
    uint8 op_cnt[4] = {0};

    if (p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS ||
        p_fp_edit->edit_type == CTC_NH_FP_EDIT_DEL )
    {
        if (p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS)
        {
            CTC_MAX_VALUE_CHECK(p_fp_edit->len, SYS_NH_FP_INS_MAX_LEGTH);
        }
        else
        {
            CTC_MAX_VALUE_CHECK(p_fp_edit->len, SYS_NH_FP_DEL_MAX_LEGTH);
        }

        if (p_fp_edit->len_from_data == 0 &&
            (p_fp_edit->len % 2 == 1))
        {
            return CTC_E_INVALID_PARAM;
        }

        if (p_fp_edit->len == 0)
        {

        }
    }

    CTC_MAX_VALUE_CHECK(p_fp_edit->offset_type, 3);
    CTC_MAX_VALUE_CHECK(p_fp_edit->offset, SYS_NH_FP_MAX_OFFSET);
    CTC_MAX_VALUE_CHECK(p_fp_edit->offset_type_ext, 3);
    CTC_MAX_VALUE_CHECK(p_fp_edit->offset_ext, SYS_NH_FP_MAX_OFFSET);

    if (p_fp_edit->next_fp_id && CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2))
    {
        return CTC_E_INVALID_CONFIG;
    }

    if (p_fp_edit->offset % 2 == 1 || p_fp_edit->offset_ext % 2 == 1)
    {
        return CTC_E_INVALID_PARAM;
    }

    if ((p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS) && (p_fp_edit->len))
    {
        CTC_PTR_VALID_CHECK(p_fp_edit->data);
    }

    CTC_MAX_VALUE_CHECK(p_fp_edit->field_cnt, 16);

    if (p_fp_edit->field_cnt)
    {
        CTC_PTR_VALID_CHECK(p_fp_edit->p_field_list);
    }

    for (i = 0; i < p_fp_edit->field_cnt; i++)
    {
        ctc_nh_fp_field_t* p_field = NULL;
        p_field = p_fp_edit->p_field_list + i;

        CTC_MIN_VALUE_CHECK(p_field->len, 1);
        CTC_MAX_VALUE_CHECK(p_field->len, 32);
        CTC_MAX_VALUE_CHECK(p_field->offset + p_field->len, 48*8);
        CTC_MAX_VALUE_CHECK(p_field->result_shift, 31);

        if (p_field->len <= 4)
        {
            if ( p_field->offset / 4 != (p_field->offset + p_field->len - 1) / 4)
            {
                return CTC_E_INVALID_PARAM;
            }
            op_cnt[0]++;
        }
        else if(p_field->len <= 8)
        {
            if ( p_field->offset / 8 != (p_field->offset + p_field->len - 1) / 8)
            {
                return CTC_E_INVALID_PARAM;
            }
            op_cnt[1]++;
        }
        else if(p_field->len <= 16)
        {
            if ( p_field->offset / 16 != (p_field->offset + p_field->len - 1) / 16)
            {
                return CTC_E_INVALID_PARAM;
            }
            op_cnt[2]++;
        }
        else if(p_field->len <= 32)
        {
            if ( p_field->offset / 32 != (p_field->offset + p_field->len - 1) / 32)
            {
                return CTC_E_INVALID_PARAM;
            }
            op_cnt[3]++;
        }

        if (op_cnt[0] > 4 || op_cnt[1] > 4 || op_cnt[2] > 4 || op_cnt[3] > 4)
        {
            return CTC_E_INVALID_PARAM;
        }

        CTC_MIN_VALUE_CHECK(p_field->data.len, 1);
        CTC_MAX_VALUE_CHECK(p_field->data.len, 32);

        if (p_field->data.type == CTC_NH_FP_DATA_PACKET)
        {
            CTC_MAX_VALUE_CHECK(p_field->data.shift, 127);
        }
        else
        {
            CTC_MAX_VALUE_CHECK(p_field->data.shift, 31);
        }

        if (p_field->data.type == CTC_NH_FP_DATA_XDATA)
        {
            CTC_MAX_VALUE_CHECK(p_field->data.src_offset, 127);
        }
        else if (p_field->data.type == CTC_NH_FP_DATA_RAW &&
            (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2) ||
            (!(SYS_NH_FP_SPECIAL_VAL(p_field->data.value)&& p_field->data.len == 4))))
        {
            sum_len += p_field->data.len;

            if (p_field->data.len <= 4)
            {
                raw[0].cnt++;
            }
            else if(p_field->data.len <= 8)
            {
                raw[1].cnt++;
            }
            else if(p_field->data.len <= 16)
            {
                raw[2].cnt++;
            }
            else if(p_field->data.len <= 32)
            {
                raw[3].cnt++;
            }
        }

        if (p_field->data_op != CTC_NH_FP_OP_NOP ||
            p_field->chk.chk_op != CTC_NH_FP_OP_NOP)
        {
            /*CTC_MIN_VALUE_CHECK(p_field->data_r.len, 1);*/
            CTC_MAX_VALUE_CHECK(p_field->data_r.len, 32);

            if (p_field->data_r.type == CTC_NH_FP_DATA_PACKET)
            {
                CTC_MAX_VALUE_CHECK(p_field->data_r.shift, 127);
            }
            else
            {
                CTC_MAX_VALUE_CHECK(p_field->data_r.shift, 31);
            }

            if (p_field->data_r.type == CTC_NH_FP_DATA_RAW &&
                (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2) ||
                (!(SYS_NH_FP_SPECIAL_VAL(p_field->data_r.value)&& p_field->data_r.len == 4))))
            {
                sum_len += p_field->data_r.len;

                if (p_field->data_r.len <= 4)
                {
                    raw[0].cnt++;
                }
                else if(p_field->data_r.len <= 8)
                {
                    raw[1].cnt++;
                }
                else if(p_field->data_r.len <= 16)
                {
                    raw[2].cnt++;
                }
                else if(p_field->data_r.len <= 32)
                {
                    raw[3].cnt++;
                }
            }

        }

        if (p_field->data_op != CTC_NH_FP_OP_NOP ||
            p_field->chk.chk_op != CTC_NH_FP_OP_NOP ||
            p_field->zone_op != CTC_NH_FP_OP_NOP )
        {
            alu_cnt++;
        }
    }

    CTC_MAX_VALUE_CHECK(alu_cnt, 4);
    if(DRV_FROM_AT(lchip) && (p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS) && (p_fp_edit->len > 16) && CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_WITHOUT_TMP))
    {
        *ext_mode = SYS_NH_FP_INST_PAIR_EXT;
    }
    else if (p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS ||
        p_fp_edit->edit_type == CTC_NH_FP_EDIT_DEL )
    {
        CTC_MAX_VALUE_CHECK(sum_len, 128);
        if (sum_len > 48)
        {
            *ext_mode = SYS_NH_FP_INST_PAIR;
        }
    }
    else
    {
        CTC_MAX_VALUE_CHECK(sum_len, 128);
        if (sum_len > 64)
        {
            *ext_mode = SYS_NH_FP_INST_PAIR;
        }
    }

    if (DRV_FROM_AT(lchip) && CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2) && (*ext_mode != 0))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "raw[0].cnt:%d, raw[1].cnt:%d, raw[2].cnt:%d, raw[3].cnt:%d\n",\
                                        raw[0].cnt, raw[1].cnt, raw[2].cnt, raw[3].cnt);
        if(raw[0].cnt > 2 || raw[1].cnt > 1 || raw[2].cnt > 4 || raw[3].cnt > 2)
        {
            return CTC_E_INVALID_PARAM;
        }

        /*4 bits use flexEditData(8,11),  (12,15)*/
        raw[0].pos = 2; /*offset 8/4*/

        /*8 bits use flexEditData(16,23)*/
        raw[1].pos = 2; /*offset 16/8*/

        /*16 bits use flexEditData(0,15),(16,31),(32,47),(48,63)*/
        if(raw[1].cnt)
        {
            raw[2].pos = 2; /*from offset 32 bits*/
        }
        else if(raw[0].cnt)
        {
            raw[2].pos = 1;
        }
        else
        {
            raw[2].pos = 0;
        }
        if((raw[2].pos+raw[2].cnt) * 16 > 64)
        {
            return CTC_E_INVALID_PARAM;
        }

        /*32 bits use flexEditData(0,31),(32,63)*/
        if(raw[3].cnt == 2 && (raw[0].cnt || raw[1].cnt || raw[2].cnt))
        {
            return CTC_E_INVALID_PARAM;
        }
        else if(raw[3].cnt == 1 && (raw[0].cnt || raw[1].cnt || raw[2].cnt))
        {
            /*check overlap*/
            if(((raw[2].pos + raw[2].cnt) * 16) > 32)
            {
                return CTC_E_INVALID_PARAM;
            }
            raw[3].pos = 1;
        }
        else
        {
            raw[3].pos = 0;
        }
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "raw[0].pos:%d, raw[1].pos:%d, raw[2].pos:%d, raw[3].pos:%d\n",\
                                        raw[0].pos, raw[1].pos, raw[2].pos, raw[3].pos);
    }
    else
    {
        raw[1].pos = (raw[0].cnt*4 + 7) / 8;
        raw[2].pos = (raw[0].cnt*4 + raw[1].cnt*8 + 15) / 16;
        raw[3].pos = (raw[0].cnt*4 + raw[1].cnt*8 + raw[2].cnt*16 + 31) / 32;

        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "sum_len:%d\n", sum_len);
        for (i = 0; i < 4; i++)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "raw[%d].pos:%d, raw[%d].cnt:%d\n",
                           i, raw[i].pos, i, raw[i].cnt);

            if ((raw[i].pos + raw[i].cnt) > 4)
            {
                return CTC_E_INVALID_PARAM;
            }

        }
    }

    return CTC_E_NONE;
}

enum sys_nh_fp_op_e
{
   SYS_NH_FP_OP_RVALUE = 0,    /**< [TMM] left value*/
   SYS_NH_FP_OP_GE  = 1,       /**< [TMM] operator >=*/
   SYS_NH_FP_OP_LE  = 2,       /**< [TMM] operator <=*/
   SYS_NH_FP_OP_ADD = 3,       /**< [TMM] operator +*/
   SYS_NH_FP_OP_SUB = 4,       /**< [TMM] operator -*/
   SYS_NH_FP_OP_SHL = 5,       /**< [TMM] operator <<*/
   SYS_NH_FP_OP_SHR = 6,       /**< [TMM] operator >>*/
   SYS_NH_FP_OP_ROL = 7,       /**< [TMM] operator <<(ROL)*/
   SYS_NH_FP_OP_ROR = 8,       /**< [TMM] operator >>(ROR)*/
   SYS_NH_FP_OP_EQ  = 9,       /**< [TMM] operator =*/
   SYS_NH_FP_OP_GT  = 10,      /**< [TMM] operator >*/
   SYS_NH_FP_OP_LT  = 11,      /**< [TMM] operator <*/
   SYS_NH_FP_OP_LVALUE  = 15,  /**< [TMM] right value*/
};
typedef enum sys_nh_fp_op_e sys_nh_fp_op_t;


STATIC int32
_sys_tmm_nh_map_data_op(uint8 lchip,
                            ctc_nh_fp_field_t* p_field, uint8* p_drv_op)
{
    uint8 drv_op = 0;

    /*add sub zero and left shift with 0, will use left value*/
    if (((CTC_NH_FP_OP_ADD == p_field->data_op) || (CTC_NH_FP_OP_SUB == p_field->data_op) || (CTC_NH_FP_OP_SHL == p_field->data_op) || (CTC_NH_FP_OP_ROL == p_field->data_op)) 
        && (0 == p_field->data.shift) && (0 == p_field->data_r.value) && (0 == p_field->result_shift) && (CTC_NH_FP_DATA_RAW == p_field->data.type))
    {
        *p_drv_op = SYS_NH_FP_OP_LVALUE;
        return CTC_E_NONE;
    }

    switch(p_field->data_op)
    {
    case CTC_NH_FP_OP_GE:
        drv_op = SYS_NH_FP_OP_GE;
        break;
    case CTC_NH_FP_OP_LE:
        drv_op = SYS_NH_FP_OP_LE;
        break;
    case CTC_NH_FP_OP_GT:
        drv_op = SYS_NH_FP_OP_GT;
        break;
    case CTC_NH_FP_OP_LT:
        drv_op = SYS_NH_FP_OP_LT;
        break;
    case CTC_NH_FP_OP_EQ:
        drv_op = SYS_NH_FP_OP_EQ;
        break;
    case CTC_NH_FP_OP_ADD:
        drv_op = SYS_NH_FP_OP_ADD;
        break;
    case CTC_NH_FP_OP_SUB:
        drv_op = SYS_NH_FP_OP_SUB;
        break;
    case CTC_NH_FP_OP_SHL:
        drv_op = SYS_NH_FP_OP_SHL;
        break;
    case CTC_NH_FP_OP_SHR:
        drv_op = SYS_NH_FP_OP_SHR;
        break;
    case CTC_NH_FP_OP_ROL:
        drv_op = SYS_NH_FP_OP_ROL;
        break;
    case CTC_NH_FP_OP_ROR:
        drv_op = SYS_NH_FP_OP_ROR;
        break;
    default:
        if (p_field->data_op != CTC_NH_FP_OP_NOP)
        {
            return CTC_E_INVALID_PARAM;
        }
        return SYS_NH_FP_OP_RVALUE;
    }

    *p_drv_op = drv_op;

   return 0;

}


STATIC int32
_sys_tmm_nh_add_fp_field(uint8 lchip,
                        sys_dsl3edit_fp_t* p_fp,
                        ctc_nh_fp_field_t* p_field,
                        uint8* f,
                        sys_nh_fp_data_raw_t raw[],
                        uint8* p_alu_cnt,
                        void* p_alu_prof,
                        ctc_nh_fp_edit_t *p_fp_edit)
{
    uint8 sel = 0;
    uint8 id = 0;
    uint8 f_seq = 0;
    uint8 edit_id = 0;
    uint8 container_type = 0;
    uint8 align = 0;
    uint8 fp2 = CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2);
    if (p_field->len <= 4)
    {
        if ( p_field->offset / 4 == (p_field->offset + p_field->len - 1) / 4)
        {
            id = 0;
            align = 4;
        }
    }
    else if(p_field->len <= 8)
    {
        if ( p_field->offset / 8 == (p_field->offset + p_field->len - 1) / 8)
        {
            id = 1;
            align = 8;
        }
    }
    else if(p_field->len <= 16)
    {
        if ( p_field->offset / 16 == (p_field->offset + p_field->len - 1) / 16)
        {
            id = 2;
            align = 16;
        }
    }
    else if(p_field->len <= 32)
    {
        if ( p_field->offset / 32 == (p_field->offset + p_field->len - 1) / 32)
        {
            id = 3;
            align = 32;
        }
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }

    if(!align)
    {
        return CTC_E_INVALID_PARAM;
    }
    f_seq = f[id];

    /*Direct Select field from container*/
    if (p_field->data_op == CTC_NH_FP_OP_NOP)
    {
        if(fp2)
        {
            CTC_ERROR_RETURN(_sys_tmm_nh_get_fp2_field_sel(lchip, p_fp, raw, &p_field->data, &container_type, &sel));
        }
        else
        {
            CTC_ERROR_RETURN(_sys_tmm_nh_get_fp_field_sel(lchip, p_fp, raw, &p_field->data, &container_type, &sel));
        }
        p_fp->f_sel[id][f_seq] = sel;

        if (container_type != id)
        {
            return CTC_E_NOT_SUPPORT;
        }
    }

    /*Use profile*/
    if (p_field->data_op != CTC_NH_FP_OP_NOP ||
        p_field->chk.chk_op != CTC_NH_FP_OP_NOP ||
    p_field->zone_op != CTC_NH_FP_OP_NOP)
    {
        uint8 drv_op = 0;
        uint16 step = 0;

        CTC_ERROR_RETURN(_sys_tmm_nh_map_data_op(lchip, p_field, &drv_op));

        step = DsL3EditFlexAluProfile_g_1_aluProfileValid_f - DsL3EditFlexAluProfile_g_0_aluProfileValid_f;
        edit_id = *p_alu_cnt;
        SetDsL3EditFlexAluProfile(V, g_0_opType_f + edit_id*step, p_alu_prof, drv_op);
        SetDsL3EditFlexAluProfile(V, g_0_editId_f + edit_id*step, p_alu_prof, f_seq);
        SetDsL3EditFlexAluProfile(V, g_0_containerType_f + edit_id*step, p_alu_prof, id);

        if (DRV_FROM_AT(lchip))
        {
            SetDsL3EditFlexAluProfile(V, g_0_aluProfileValid_f + edit_id*step, p_alu_prof, 1);
        }

        /*data op*/
        if (p_field->data_op != CTC_NH_FP_OP_NOP || p_field->chk.chk_op != CTC_NH_FP_OP_NOP)
        {

            if (!DRV_FROM_AT(lchip))
            {
                SetDsL3EditFlexAluProfile(V, g_0_aluProfileValid_f + edit_id*step, p_alu_prof, 1);
            }

            /*DataL*/
            if(fp2)
            {
                CTC_ERROR_RETURN(_sys_tmm_nh_get_fp2_field_sel(lchip, p_fp, raw, &p_field->data, &container_type, &sel));
            }
            else
            {
                CTC_ERROR_RETURN(_sys_tmm_nh_get_fp_field_sel(lchip, p_fp, raw, &p_field->data, &container_type, &sel));
            }
            SetDsL3EditFlexAluProfile(V, g_0_containerTypeL_f + edit_id*step, p_alu_prof, container_type);
            SetDsL3EditFlexAluProfile(V, g_0_dataSelL_f + edit_id*step, p_alu_prof, sel);
            SetDsL3EditFlexAluProfile(V, g_0_dataMaskL_f + edit_id*step, p_alu_prof, p_field->data.mask == 0? 0xFFFFFFFF: p_field->data.mask);
            SetDsL3EditFlexAluProfile(V, g_0_dataShiftL_f + edit_id*step, p_alu_prof, p_field->data.shift%32);

            /*DataR*/
            if(fp2)
            {
                CTC_ERROR_RETURN(_sys_tmm_nh_get_fp2_field_sel(lchip, p_fp, raw, &p_field->data_r, &container_type,  &sel));
            }
            else
            {
                CTC_ERROR_RETURN(_sys_tmm_nh_get_fp_field_sel(lchip, p_fp, raw, &p_field->data_r, &container_type,  &sel));
            }
            SetDsL3EditFlexAluProfile(V, g_0_containerTypeR_f + edit_id*step, p_alu_prof, container_type);
            SetDsL3EditFlexAluProfile(V, g_0_dataSelR_f + edit_id*step, p_alu_prof, sel);
            SetDsL3EditFlexAluProfile(V, g_0_dataMaskR_f + edit_id*step, p_alu_prof, p_field->data_r.mask == 0? 0xFFFFFFFF: p_field->data_r.mask);
            SetDsL3EditFlexAluProfile(V, g_0_dataShiftR_f + edit_id*step, p_alu_prof, p_field->data_r.shift%32);

            SetDsL3EditFlexAluProfile(V, g_0_resultShift_f + edit_id*step, p_alu_prof, p_field->result_shift%32);

            p_fp->f_sel[id][f_seq] = 0;
        }

        /*pending op*/
        if (p_field->zone_op != CTC_NH_FP_OP_NOP)
        {
            uint8 op = 0;

            SetDsL3EditFlexAluProfile(V, g_0_dataTypeL_f + edit_id*step, p_alu_prof, 1);
            SetDsL3EditFlexAluProfile(V, g_0_dataTypeR_f + edit_id*step, p_alu_prof,
             (DRV_FROM_AT(lchip)&& p_field->data_op == CTC_NH_FP_OP_NOP && p_field->chk.chk_op == CTC_NH_FP_OP_NOP) ? 1 : 0);

            if (p_field->zone_op == CTC_NH_FP_OP_ADD)
            {
                op = 1;
            }
            else if(p_field->zone_op == CTC_NH_FP_OP_SUB)
            {
                op = 2;
            }

            SetDsL3EditFlexAluProfile(V, g_0_opType1_f + edit_id*step, p_alu_prof, op);
        }

        /*discard*/
        if (p_field->chk.chk_op != CTC_NH_FP_OP_NOP)
        {
            uint8 op_vec = 0;
            uint8 op_mask = 0;
            uint8 chk_op  = 0;

            if (p_field->chk.to_cpu)
            {
                SetDsL3EditFlexAluProfile(V, g_0_exceptionEn_f + edit_id*step, p_alu_prof, 1);
                SetDsL3EditFlexAluProfile(V, g_0_exceptionIndex_f + edit_id*step, p_alu_prof, 0);
                SetDsL3EditFlexAluProfile(V, g_0_exceptionSubIndex_f + edit_id*step, p_alu_prof, 2);
            }

            if (p_field->chk.discard)
            {
                SetDsL3EditFlexAluProfile(V, g_0_discardEn_f + edit_id*step, p_alu_prof, 1);
                SetDsL3EditFlexAluProfile(V, g_0_discardType_f + edit_id*step, p_alu_prof, 0x29);/*EPEDISCARDTYPE_DS_L3EDIT_DATA_VIOLATE1*/
            }

            /*
    checkResultVec(0) = DsL3EditFlexAluProfile.g[id].checkOpMask(0) | (DsL3EditFlexAluProfile.g[id].checkOpVec(0) ? ((~aluDataTemp1(32))) : aluDataTemp1(32));
    checkResultVec(1) = DsL3EditFlexAluProfile.g[id].checkOpMask(1) | (DsL3EditFlexAluProfile.g[id].checkOpVec(1) ? ((~aluDataEqual)) : aluDataEqual);
    checkResult = DsL3EditFlexAluProfile.g[id].checkOpType ? ((*checkResultVec(1,0))) : ((+checkResultVec(1,0)));
            */

            if (p_field->chk.chk_op == CTC_NH_FP_OP_GE)
            {
                op_vec = 0; /*>=*/
                op_mask = 2; /*= mask*/
                chk_op  = 1; /*and*/
            }
            else if(p_field->chk.chk_op == CTC_NH_FP_OP_LT)
            {
                op_vec = 1; /*<*/
                op_mask = 2; /*= mask*/
                chk_op  = 1;/*and*/
            }
            else if(p_field->chk.chk_op == CTC_NH_FP_OP_EQ)
            {
                op_vec = 0; /*=*/
                op_mask = 1;  /*<> mask*/
                chk_op  = 1; /*and*/
            }
            else if(p_field->chk.chk_op == CTC_NH_FP_OP_NE)
            {
                op_vec = 2; /*!=*/
                op_mask = 1;  /*<> mask*/
                chk_op  = 1; /*and*/
            }
            else if(p_field->chk.chk_op == CTC_NH_FP_OP_GT)
            {
                op_vec =  2; /*>=  and  !=*/
                op_mask = 0;
                chk_op  = 1;/*and*/
            }
            else if(p_field->chk.chk_op == CTC_NH_FP_OP_LE)
            {
                op_vec = 1; /*< or =*/
                op_mask = 0;
                chk_op  = 0;/*or*/
            }
            else
            {
                return CTC_E_INVALID_PARAM;
            }

            SetDsL3EditFlexAluProfile(V, g_0_checkOpVec_f + edit_id*step, p_alu_prof, op_vec);
            SetDsL3EditFlexAluProfile(V, g_0_checkOpMask_f + edit_id*step, p_alu_prof, op_mask);
            SetDsL3EditFlexAluProfile(V, g_0_checkOpType_f + edit_id*step, p_alu_prof, chk_op);

        }

        (*p_alu_cnt)++;

    }

    p_fp->f_pos[id][f_seq]   = p_field->offset / align;
    p_fp->f_shift[id][f_seq] = align - (p_field->offset + p_field->len)%align;
    p_fp->f_zone[id][f_seq]  = p_field->zone;

    if (p_field->chk.chk_op != CTC_NH_FP_OP_NOP && p_field->data_op == CTC_NH_FP_OP_NOP)
    {
        p_fp->f_valid[id][f_seq] = 0;
    }
    else
    {
        p_fp->f_valid[id][f_seq] = 1;
        /*if field op valid, set rw zone*/
        CTC_BIT_SET(p_fp->rw_zone, p_fp->f_zone[id][f_seq]);
    }

    if (id == 3) /*32 bits,  mask type*/
    {

    }
    else if (id == 2) /*16 bits,  mask type*/
    {
        p_fp->f_mask[id][f_seq]  = 15 - p_field->offset % 16;
    }
    else if(id == 1) /*8bits*/
    {
        if (p_field->len == align)
        {
            p_fp->f_mask[id][f_seq]  = 0xFF;
        }
        else
        {
            p_fp->f_mask[id][f_seq]  = ((1 << p_field->len) - 1) << (p_fp->f_shift[id][f_seq]%8);
        }
    }
    else if(id == 0)/*4bits*/
    {
        if (p_field->len == align)
        {
            p_fp->f_mask[id][f_seq]  = 0xF;
        }
        else
        {
            p_fp->f_mask[id][f_seq]  = ((1 << p_field->len) - 1) << (p_fp->f_shift[id][f_seq]%4);
        }
    }

    f[id]++;

    return 0;
}


STATIC int32
_sys_tmm_nh_free_resource(uint8 lchip, sys_nh_fp_db_t* p_fp_db, uint8 in_update)
{
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    uint8 fp2 = DRV_FROM_AT(lchip) && p_fp_db->fp2;
    uint32 entry_type = fp2? SYS_NH_ENTRY_TYPE_XFP_EDIT : SYS_NH_ENTRY_TYPE_L3EDIT_FP + SYS_NH_TYPE_STEP_TO_INNER;
    uint32 entry_type_pair = SYS_NH_ENTRY_TYPE_L3EDIT_FP;
    if(DRV_FROM_AT(lchip) && (SYS_NH_FP_INST_PAIR_EXT == p_fp_db->ext_mode))
    {
        entry_type_pair = SYS_NH_ENTRY_TYPE_L3EDIT_FP + SYS_NH_TYPE_STEP_TO_INNER;
        entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_FP;
    }

    if (p_fp_db->p_l4chksum_prof)
    {
        CTC_ERROR_RETURN(ctc_spool_remove(p_nh_master->p_fp_spool,
                                          p_fp_db->p_l4chksum_prof, NULL));
       p_fp_db->p_l4chksum_prof = 0;
    }

    if (p_fp_db->p_l3chksum_prof)
    {
        CTC_ERROR_RETURN(ctc_spool_remove(p_nh_master->p_fp_spool,
                                          p_fp_db->p_l3chksum_prof, NULL));
        p_fp_db->p_l3chksum_prof = 0;
    }

    if (p_fp_db->p_data_prof)
    {
        CTC_ERROR_RETURN(ctc_spool_remove(p_nh_master->p_fp_spool,
                                          p_fp_db->p_data_prof, NULL));
       p_fp_db->p_data_prof = 0;
    }

    if (p_fp_db->p_alu_prof)
    {
        CTC_ERROR_RETURN(ctc_spool_remove(p_nh_master->p_fp_spool,
                                          p_fp_db->p_alu_prof, NULL));
        p_fp_db->p_alu_prof = 0;
    }

    if (p_fp_db->l3_edit_ptr && (0 == in_update))
    {
        CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip,
                                                entry_type, 1,
                                                p_fp_db->l3_edit_ptr));
       p_fp_db->l3_edit_ptr = 0;
    }

    if (p_fp_db->pair_edit_ptr && (0 == in_update))
    {
        CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip,
                                                entry_type_pair, 1,
                                                p_fp_db->pair_edit_ptr));
        p_fp_db->pair_edit_ptr = 0;
    }

    return CTC_E_NONE;
}

int32
_sys_tmm_nh_add_fp(uint8 lchip,
                      ctc_nh_fp_edit_t *p_fp_edit,
                      sys_nh_fp_db_t* p_fp_db,
                      sys_nh_fp_data_raw_t raw[])
{
    uint8 i = 0;
    uint8 alu_cnt = 0;
    uint8 f[4] = {0};
    sys_dsl3edit_fp_t fp;
    sys_nh_fp_prof_t alu_prof;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    uint8 fp2 = DRV_FROM_AT(lchip) && CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2);
    uint32 entry_type = fp2? SYS_NH_ENTRY_TYPE_XFP_EDIT : SYS_NH_ENTRY_TYPE_L3EDIT_FP + SYS_NH_TYPE_STEP_TO_INNER;
    uint32 entry_type_pair = SYS_NH_ENTRY_TYPE_L3EDIT_FP;

    /* Allocate new dsl3edit fp entry*/
    if(DRV_FROM_AT(lchip) && (SYS_NH_FP_INST_PAIR_EXT == p_fp_db->ext_mode))
    {
        entry_type_pair = SYS_NH_ENTRY_TYPE_L3EDIT_FP + SYS_NH_TYPE_STEP_TO_INNER;
        entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_FP;
    }
    else
    {
        /* use default */
    }

    if (0 == p_fp_db->l3_edit_ptr)
    {
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, entry_type, 1,
                                                 &p_fp_db->l3_edit_ptr));
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "alloc l3_edit_ptr:%u \n", p_fp_db->l3_edit_ptr);

    if ((p_fp_db->ext_mode) && (0 == p_fp_db->pair_edit_ptr))
    {
        /* Allocate pair dsl3edit fp entry*/
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, entry_type_pair, 1,
                                               &p_fp_db->pair_edit_ptr));
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "alloc pair_edit_ptr:%u \n", p_fp_db->pair_edit_ptr);


    sal_memset(&fp, 0, sizeof(fp));
    sal_memset(&alu_prof, 0, sizeof(alu_prof));

    switch(p_fp_edit->edit_type)
    {
    case CTC_NH_FP_EDIT_INS:
        if (SYS_NH_FP_INST_PAIR_EXT == p_fp_db->ext_mode)
        {
            fp.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_INSFLEX8X);
        }
        else
        {
            fp.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_INSFLEX);
        }
        break;

    case CTC_NH_FP_EDIT_DEL:
        fp.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_DELFLEX);
        break;

    case CTC_NH_FP_EDIT_REP:
        fp.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWFLEX);
        break;

    default:
        return CTC_E_INVALID_PARAM;
        break;
    }

    fp.layer_offset_type = p_fp_edit->offset_type;
    fp.layer_offset = p_fp_edit->offset;

    fp.layer_offset_type0 = p_fp_edit->offset_type_ext;
    fp.layer_offset0 = p_fp_edit->offset_ext;
    fp.op_seg_sel = p_fp_edit->ext_use_outer << 1 | (p_fp_edit->use_outer?1:0);

    if (p_fp_edit->len_from_data)
    {
        uint8 container_type = 0;
        uint8 sel = 0;

        if(fp2)
        {
            CTC_ERROR_RETURN(_sys_tmm_nh_get_fp2_field_sel(lchip, &fp, raw,
                                                          &p_fp_edit->length,
                                                          &container_type, &sel));
        }
        else
        {
            CTC_ERROR_RETURN(_sys_tmm_nh_get_fp_field_sel(lchip, &fp, raw,
                                                          &p_fp_edit->length,
                                                          &container_type, &sel));
        }
        fp.ins_del_len  = sel;
        fp.len_from_data = 1;
    }
    else
    {
        fp.ins_del_len = p_fp_edit->len;
    }

    for (i = 0; i < p_fp_edit->field_cnt; i++)
    {
        CTC_ERROR_RETURN(_sys_tmm_nh_add_fp_field(lchip, &fp,
                                                 p_fp_edit->p_field_list + i,
                                                 f, raw, &alu_cnt, alu_prof.data,
                                                 p_fp_edit));
    }

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_FP, 1);

    if (alu_cnt)
    {
        sys_nh_fp_prof_t* p_alu_prof = NULL;

        /*update spool*/
        alu_prof.type = fp2 ? SYS_NH_ENTRY_TYPE_XFP_ALU_PROFILE : SYS_NH_ENTRY_TYPE_FP_ALU_PROFILE;
        CTC_ERROR_RETURN(ctc_spool_add(p_nh_master->p_fp_spool,
                                       &alu_prof, NULL, &p_alu_prof));

        /*write alu profile hardware*/
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip,
                                    fp2? SYS_NH_ENTRY_TYPE_XFP_ALU_PROFILE : SYS_NH_ENTRY_TYPE_FP_ALU_PROFILE,
                                    p_alu_prof->profile_id,
                                    alu_prof.data));

        fp.alu_profile = p_alu_prof->profile_id;
        p_fp_db->p_alu_prof = p_alu_prof;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "alu profile_id:%u \n", p_alu_prof->profile_id);

    }

    if ((p_fp_edit->edit_type == CTC_NH_FP_EDIT_INS) && p_fp_edit->len && (SYS_NH_FP_INST_PAIR_EXT != p_fp_db->ext_mode))/*only arctic have 8x*/
    {
        int16 len = 0;
        uint16 i = 0;
        uint32 *drv_data = NULL;
        sys_nh_fp_prof_t* p_data_prof = NULL;
        sys_nh_fp_prof_t data_prof;

        sal_memset(&data_prof, 0, sizeof(data_prof));

        data_prof.type = fp2? SYS_NH_ENTRY_TYPE_XFP_DATA_PROFILE : SYS_NH_ENTRY_TYPE_FP_DATA_PROFILE;

         len =  p_fp_edit->len;
         drv_data = data_prof.data;
        while (len > 0)
        {
            if (len >= 4)
            {
                drv_data[i] = (p_fp_edit->data[i*4] << 24) | (p_fp_edit->data[i*4 + 1] << 16) | (p_fp_edit->data[i*4 + 2] <<8) | p_fp_edit->data[i*4 + 3];
                len = len - 4;
                i++;
            }
            else if (len == 3)
            {
                drv_data[i] = (p_fp_edit->data[i*4] << 24) | (p_fp_edit->data[i*4 + 1] << 16) | (p_fp_edit->data[i*4 + 2] <<8);
                len = 0;
            }
            else if (len == 2)
            {
                drv_data[i] = (p_fp_edit->data[i*4] << 24) | (p_fp_edit->data[i*4 + 1] << 16);
                len = 0;
            }
            else
            {
                drv_data[i] = (p_fp_edit->data[i*4] << 24);
                len = 0;
            }
        }


        //sal_memcpy(data_prof.data, p_fp_edit->data, p_fp_edit->len);
        CTC_ERROR_RETURN(ctc_spool_add(p_nh_master->p_fp_spool,
                                       &data_prof, NULL, &p_data_prof));

        /*write data profile hardware*/
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip,
                                    fp2? SYS_NH_ENTRY_TYPE_XFP_DATA_PROFILE : SYS_NH_ENTRY_TYPE_FP_DATA_PROFILE,
                                    p_data_prof->profile_id,
                                    data_prof.data));

        fp.ins_profile_id = p_data_prof->profile_id;
        p_fp_db->p_data_prof = p_data_prof;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "data profile_id:%u \n", p_data_prof->profile_id);
    }

    if (p_fp_edit->l3chksum.enable)
    {
        if(p_fp_edit->l3chksum.offset != 0xFF)
        {
            sys_nh_fp_prof_t* p_l3chksum_prof = NULL;
            sys_nh_fp_prof_t l3chsum_prof;
            uint32 mask = 0;

            sal_memset(&l3chsum_prof, 0, sizeof(l3chsum_prof));
            l3chsum_prof.type = SYS_NH_ENTRY_TYPE_FP_L3CHKSUM_PROFILE;
            mask = ~(p_fp_edit->l3chksum.mask);
            sal_memcpy(l3chsum_prof.data, &mask, sizeof(mask));
            CTC_ERROR_RETURN(ctc_spool_add(p_nh_master->p_fp_spool,
                                           &l3chsum_prof, NULL, &p_l3chksum_prof));

            /*write l3chksum profile hardware*/
            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip,
                                                         SYS_NH_ENTRY_TYPE_FP_L3CHKSUM_PROFILE,
                                                         p_l3chksum_prof->profile_id,
                                                         l3chsum_prof.data));
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "l3 chksum profile_id:%u \n", p_l3chksum_prof->profile_id);

            p_fp_db->p_l3chksum_prof = p_l3chksum_prof;
            fp.l3_chksum_mask_id = p_l3chksum_prof->profile_id;
            fp.l3_chksum_sel =  ((1 << 4) | p_fp_edit->l3chksum.offset);
        }
        else
        {
            fp.l3_chksum_mask_id = 0;
            fp.l3_chksum_sel = 0;
        }

        fp.l3_chksum_update = 1;
        fp.l3_chksum_updatex = p_fp_edit->l3chksum.extra_update;

    }

    if (p_fp_edit->l4chksum.enable)
    {
        if(p_fp_edit->l4chksum.offset != 0xFF)
        {
            sys_nh_fp_prof_t* p_l4chksum_prof = NULL;
            sys_nh_fp_prof_t l4chsum_prof;
            uint32 mask = 0;

            sal_memset(&l4chsum_prof, 0, sizeof(l4chsum_prof));

            l4chsum_prof.type = SYS_NH_ENTRY_TYPE_FP_L4CHKSUM_PROFILE;
            mask = ~(p_fp_edit->l4chksum.mask);

            sal_memcpy(l4chsum_prof.data, &mask, sizeof(mask));
            CTC_ERROR_RETURN(ctc_spool_add(p_nh_master->p_fp_spool,
                                           &l4chsum_prof, NULL, &p_l4chksum_prof));

            /*write l4chksum profile hardware*/
            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip,
                                                         SYS_NH_ENTRY_TYPE_FP_L4CHKSUM_PROFILE,
                                                         p_l4chksum_prof->profile_id,
                                                         l4chsum_prof.data));

            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "l4 chksum profile_id:%u \n", p_l4chksum_prof->profile_id);

            p_fp_db->p_l4chksum_prof = p_l4chksum_prof;
            fp.l4_chksum_mask_id = p_l4chksum_prof->profile_id;
            fp.l4_chksum_sel =  ((1 << 4) | p_fp_edit->l4chksum.offset);
        }
        else
        {
            fp.l4_chksum_mask_id = 0;
            fp.l4_chksum_sel = 0;
        }

        fp.l4_chksum_update = 1;
        fp.l4_chksum_updatex = p_fp_edit->l4chksum.extra_update;

    }

    fp.rw_data_sel = CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2)? 1 : 2;
    if (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_REP_SEL_VALID))
    {
        fp.rw_data_sel = p_fp_edit->replace_sel;
    }
    fp.l3_len_update = CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_KEEP_L3_LEN)?0:1;
    fp.l4_len_update = CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_KEEP_L4_LEN)?0:1;

    if(p_fp_edit->next_fp_id)
    {
        sys_nh_fp_db_t tmp_fp_db;
        sys_nh_fp_db_t* p_tmp_fp_db = NULL;
        sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));
        tmp_fp_db.fp_id = p_fp_edit->next_fp_id;
        p_tmp_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);
        if (NULL == p_tmp_fp_db)
        {
            return CTC_E_ENTRY_NOT_EXIST;
        }
        if (0 == p_tmp_fp_db->fp2)
        {
            return CTC_E_INVALID_PARAM;
        }

        fp.xedit_ptr = p_tmp_fp_db->l3_edit_ptr;
    }

    /*write fp hardware*/
    CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip, entry_type, p_fp_db->l3_edit_ptr, &fp));

    if (p_fp_db->pair_edit_ptr)
    {
        uint8 bit_width = 0;
        sys_dsl3edit_fp_t fp_pair;

/*       DRV_DEF_F(CModel, 1, DsL3EditInsFlex, data1, data1, 80, {14, 0, 2}, {13, 30, 2}, {13, 29, 1}, {13, 28, 1}, {13, 23, 5}, {13, 19, 4}, {13, 18, 1}, {13, 17, 1}, {13, 15, 2}, {13, 9, 6}, {13, 7, 2}, {14, 7, 6}, {13, 0, 1}, {12, 0, 32}, {11, 0, 4}, {10, 21, 11})
 */
        sal_memset(&fp_pair, 0, sizeof(fp_pair));
        fp_pair.l3_rewrite_type = fp.l3_rewrite_type;
        fp_pair.ext_mode = p_fp_db->ext_mode;

        if (SYS_NH_FP_INST_PAIR_EXT == p_fp_db->ext_mode)
        {
            sal_memcpy((uint32*)fp_pair.raw_data, (uint32*)p_fp_edit->data, p_fp_edit->len);
        }
        else
        {
            bit_width = p_fp_edit->edit_type == CTC_NH_FP_EDIT_REP?64:48;
            CTC_BMP_COPY_RANGE(fp_pair.raw_data, 0, fp.raw_data,  bit_width, (128 - bit_width));
        }
        /*write fp hardware*/
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table( lchip,
                                                  entry_type_pair,
                                                  p_fp_db->pair_edit_ptr,
                                                  &fp_pair));
    }

    return CTC_E_NONE;

}

int32
sys_tmm_nh_add_fp(uint8 lchip, void* p_fp_edit_v, uint8 is_internal)
{
    sys_nh_fp_data_raw_t raw[4];
    int32 ret = 0;
    uint32 fp_id = 0;
    uint8 ext_mode = 0;
    sys_nh_fp_db_t tmp_fp_db;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    sys_nh_fp_db_t* p_fp_db = NULL;
    ctc_nh_fp_edit_t* p_fp_edit = (ctc_nh_fp_edit_t*)p_fp_edit_v;

    /* Check */
    CTC_PTR_VALID_CHECK(p_fp_edit);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "fp_id:%u \n", p_fp_edit->fp_id);

    sal_memset(raw, 0, sizeof(raw));

#ifdef WARMBOOT
    if (p_nh_master->fp_id_hash->count >= SYS_NH_FP_NUM)
    {
        return CTC_E_NO_RESOURCE;
    }
#endif

    CTC_ERROR_RETURN(_sys_tmm_nh_fp_check(lchip, p_fp_edit, &ext_mode, raw));

    /* FP id alloc and check*/
    if (p_fp_edit->fp_id == 0)
    {
        sys_usw_opf_t opf;
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = g_usw_nh_master[lchip]->fp_opf_type;
        opf.pool_index = 0;
        opf.reverse = is_internal;
        CTC_ERROR_RETURN(sys_usw_opf_alloc_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, 1, &fp_id));
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "alloc fp_id:%u \n", fp_id);
    }
    else
    {
        sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));
        tmp_fp_db.fp_id = p_fp_edit->fp_id;
        p_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);
        if (NULL != p_fp_db)
        {
            return CTC_E_ENTRY_EXIST;
        }
        fp_id = p_fp_edit->fp_id;
    }

    /* fp DB Alloc*/
    p_fp_db = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_fp_db_t));
    if (NULL == p_fp_db)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto Error0;
    }

    sal_memset(p_fp_db, 0, sizeof(sys_nh_fp_db_t));
    p_fp_db->alloc_en = (p_fp_edit->fp_id == 0);
    p_fp_db->fp_id = fp_id;
    p_fp_db->fp2 = CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2)?1:0;
    p_fp_db->ext_mode = ext_mode;
    p_fp_db->is_internal = is_internal;
    /*fp process*/
    ret = _sys_tmm_nh_add_fp(lchip, p_fp_edit, p_fp_db, raw);
    if (CTC_E_NONE != ret)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "_sys_tmm_nh_add_fp fail\n");
        goto Error1;
    }


    /*insert to DB*/
    ctc_hash_insert(p_nh_master->fp_id_hash, p_fp_db);

    /* return fp id*/
    if (0 == p_fp_edit->fp_id)
    {
        p_fp_edit->fp_id = fp_id;
    }

    return CTC_E_NONE;


Error1:
      _sys_tmm_nh_free_resource(lchip, p_fp_db, 0);
      mem_free(p_fp_db);
Error0:

    if (p_fp_edit->fp_id == 0)
    {
        sys_usw_opf_t opf;
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = g_usw_nh_master[lchip]->fp_opf_type;
        opf.pool_index = 0;
        opf.reverse = is_internal;
        CTC_ERROR_RETURN(sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, 1, fp_id));
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "free fp_id:%u \n", fp_id);
    }

    return ret;

}


int32
sys_tmm_nh_update_fp(uint8 lchip, void* p_fp_edit_v)
{
    sys_nh_fp_data_raw_t raw[4];
    int32 ret = 0;
    uint8 ext_mode = 0;
    sys_nh_fp_db_t tmp_fp_db;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    sys_nh_fp_db_t* p_fp_db = NULL;
    sys_nh_fp_db_t fp_db_old;
    ctc_nh_fp_edit_t* p_fp_edit = (ctc_nh_fp_edit_t*)p_fp_edit_v;

    /* Check */
    CTC_PTR_VALID_CHECK(p_fp_edit);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "fp_id:%u \n", p_fp_edit->fp_id);

    sal_memset(raw, 0, sizeof(raw));

    CTC_ERROR_RETURN(_sys_tmm_nh_fp_check(lchip, p_fp_edit, &ext_mode, raw));

    /* FP id alloc and check*/
    if (p_fp_edit->fp_id == 0)
    {
        return CTC_E_INVALID_PARAM;
    }

    sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));
    tmp_fp_db.fp_id = p_fp_edit->fp_id;
    p_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);
    if (NULL == p_fp_db)
    {
        return CTC_E_NOT_EXIST;
    }

    if (p_fp_db->fp2 != CTC_FLAG_ISSET(p_fp_edit->flag, CTC_NH_FP_FLAG_STAGE2))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (p_fp_db->ext_mode != ext_mode)
    {
        return CTC_E_INVALID_CONFIG;
    }

    sal_memcpy(&fp_db_old, p_fp_db, sizeof(sys_nh_fp_db_t));

    sal_memset(p_fp_db, 0, sizeof(sys_nh_fp_db_t));
    p_fp_db->fp_id = fp_db_old.fp_id;
    p_fp_db->alloc_en = fp_db_old.alloc_en;
    p_fp_db->fp2 = fp_db_old.fp2;
    p_fp_db->ext_mode = ext_mode;
    p_fp_db->l3_edit_ptr = fp_db_old.l3_edit_ptr;/*for update*/
    p_fp_db->pair_edit_ptr = fp_db_old.pair_edit_ptr;/*for update*/
    p_fp_db->is_internal = fp_db_old.is_internal;
    /*fp process*/
    ret = _sys_tmm_nh_add_fp(lchip, p_fp_edit, p_fp_db, raw);
    if (ret != CTC_E_NONE)
    {
        CTC_ERROR_RETURN(_sys_tmm_nh_free_resource(lchip, p_fp_db, 1));
        sal_memcpy(p_fp_db, &fp_db_old, sizeof(sys_nh_fp_db_t));
        return ret;
    }

    /*free old*/
    CTC_ERROR_RETURN(_sys_tmm_nh_free_resource(lchip, &fp_db_old, 1));

    return CTC_E_NONE;

}

int32
sys_tmm_nh_remove_fp(uint8 lchip, uint32 fp_id)
{
    sys_nh_fp_db_t* p_fp_db = NULL;
    sys_nh_fp_db_t tmp_fp_db;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];

    sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));

    tmp_fp_db.fp_id = fp_id;
    p_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);

    if (NULL == p_fp_db)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    CTC_ERROR_RETURN(_sys_tmm_nh_free_resource(lchip, p_fp_db, 0));

    if (p_fp_db->alloc_en)
    {
        sys_usw_opf_t opf;
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = p_nh_master->fp_opf_type;
        opf.pool_index = 0;
        CTC_ERROR_RETURN(sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, 1, p_fp_db->fp_id));
    }

    ctc_hash_remove(p_nh_master->fp_id_hash, p_fp_db);

    if (p_fp_db)
    {
        mem_free(p_fp_db);
    }

    return CTC_E_NONE;
}

int32
sys_tmm_nh_get_fp_db(uint8 lchip, uint32 fp_id, void** pp_nh_fp_db_v)
{
    sys_nh_fp_db_t tmp_fp_db;
    sys_nh_fp_db_t* p_fp_db = NULL;
    sys_nh_fp_db_t** pp_nh_fp_db = (sys_nh_fp_db_t**)pp_nh_fp_db_v;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];

    sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));

    tmp_fp_db.fp_id = fp_id;
    p_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);

    if (NULL == p_fp_db)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    *pp_nh_fp_db = p_fp_db;

    return CTC_E_NONE;
}


int32
sys_tmm_nh_get_fp_info(uint8 lchip, uint32 fp_id, void* p_fp_info_v)
{
    sys_nh_fp_db_t tmp_fp_db;
    sys_nh_fp_db_t* p_fp_db = NULL;
    sys_nh_info_dsnh_t* p_fp_info = (sys_nh_info_dsnh_t*)p_fp_info_v;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];

    sal_memset(&tmp_fp_db, 0, sizeof(tmp_fp_db));

    tmp_fp_db.fp_id = fp_id;
    p_fp_db = ctc_hash_lookup(p_nh_master->fp_id_hash, &tmp_fp_db);

    if (NULL == p_fp_db)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    p_fp_info->l3_edit_ptr = p_fp_db->l3_edit_ptr;
    p_fp_info->pair_edit_ptr = p_fp_db->pair_edit_ptr;
    if (DRV_FROM_AT(lchip) && (SYS_NH_FP_INST_PAIR_EXT == p_fp_db->ext_mode))
    {
        p_fp_info->l3_edit_ptr = p_fp_db->pair_edit_ptr;/*inner edit*/
        p_fp_info->pair_edit_ptr = p_fp_db->l3_edit_ptr;/*outer edit*/
    }
    p_fp_info->fp2 = p_fp_db->fp2;
    return CTC_E_NONE;
}


int32
sys_tmm_nh_fp_init(uint8 lchip)
{
    int32 ret = 0;
    uint8 opf_type = 0;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    ctc_spool_t spool;
    sys_usw_opf_t opf;

    /* fp spool init */
    sal_memset(&spool, 0, sizeof(ctc_spool_t));
    spool.lchip = lchip;
    spool.block_num = 1;
    spool.block_size = 1024; /*256 + 128*/
    spool.max_count = 1024;  /*256 + 128*/
    spool.user_data_size = sizeof(sys_nh_fp_prof_t);
    spool.spool_key = (hash_key_fn) _sys_tmm_nh_fp_spool_make;
    spool.spool_cmp = (hash_cmp_fn) _sys_tmm_nh_fp_spool_cmp;
    spool.spool_alloc = (spool_alloc_fn)_sys_tmm_nh_fp_spool_alloc_index;
    spool.spool_free = (spool_free_fn)_sys_tmm_nh_fp_spool_free_index;
    p_nh_master->p_fp_spool = ctc_spool_create(&spool);
    if (!p_nh_master->p_fp_spool)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto clean;
    }

    p_nh_master->fp_id_hash = ctc_hash_create(SYS_NH_FP_HASH_SIZE/CTC_HASH_512_BLOCK_SIZE,
                                                    CTC_HASH_512_BLOCK_SIZE,
                                                    (hash_key_fn)_sys_tmm_nh_fp_hash_make,
                                                    (hash_cmp_fn)_sys_tmm_nh_fp_hash_cmp);
    if (!p_nh_master->fp_id_hash)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto clean;
    }

    /* init opf for fp id*/
    CTC_ERROR_RETURN(sys_usw_opf_init(lchip, &opf_type, 2,  "opf-nh-fp"));
    g_usw_nh_master[lchip]->fp_opf_type = opf_type;
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_type = opf_type;
    opf.pool_index = 0;
    CTC_ERROR_RETURN(sys_usw_opf_init_offset(lchip, &opf, 1, 0xFFFF));

    CTC_ERROR_RETURN(_sys_tmm_nh_fp_init_reg(lchip));

clean:

    return ret;
}


